using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SpeedSearch.FullText;
using Speed;
using System.Diagnostics;
using SpeedSearch.Forms;
using System.IO;

namespace SpeedSearch.Controls
{

    public partial class CtlSearch : UserControl
    {

        Dictionary<int, DocSearcher2> searchers;
        List<DocFile> results;
        List<DocFile> removed;
        bool isSearching;

        static int PageIndex = 0;

        public CtlSearch()
        {
            InitializeComponent();
        }

        private void CtlSearch_Load(object sender, EventArgs e)
        {
            if (!DesignMode)
            {
                PageIndex++;

                this.Disposed += (o, ev) =>
                    {
                        foreach (var searcher in searchers)
                            searcher.Value.Dispose();
                    };

                //this.tsbSearch.Image = DL3D.Properties.Resources.Go;
                cboIndexes.DisplayMember = "IndexName";
                Program.Db.Indexes.DefaultView.Sort = "IndexName";
                cboIndexes.DataSource = Program.Db.Indexes.OrderBy(p => p.IndexName).ToList();

#if DEBUG
                cboSearch.Text = "class";
#endif

                this.GotFocus += (o, ev) => cboSearch.Focus();

                btnSelectAll.Click += (o, ev) => SelectAll(clbFolders, true);
                btnDeselectAll.Click += (o, ev) => SelectAll(clbFolders, false);
                lblExtSelectAll.Click += (o, ev) => SelectAll(clbExtensions, true);
                lblExtDeSelectAll.Click += (o, ev) => SelectAll(clbExtensions, false);

                cboSearch.Enter += (o, ev) => cboSearch.SelectAll();
                cboSearch.KeyDown += new KeyEventHandler(cboSearch_KeyDown);
                cboSearch.TextChanged += (o, ev) => SetControls();

                cboSearchMode.DisplayMember = "Text";
                cboSearchMode.ValueMember = "Value";
                cboSearchMode.Items.Add(new DataItem { Text = "Todas as palavras", Value = EnumSearchMode.And });
                cboSearchMode.Items.Add(new DataItem { Text = "Qualquer uma das palavras", Value = EnumSearchMode.Or });
                cboSearchMode.Items.Add(new DataItem { Text = "Frase exata", Value = EnumSearchMode.Exact });
                cboSearchMode.Items.Add(new DataItem { Text = "Pequisa lógica", Value = EnumSearchMode.Boolean });
                cboSearchMode.SelectedIndex = 0;
                //cboSearchMode.SelectedIndexChanged += (o, ev) => { Search(); };

                cboFields.Items.Add(new DataItem { Text = "Conteúdo", Value = "text", Tag = "" });
                cboFields.Items.Add(new DataItem { Text = "Caminho completo", Value = "fname", Tag = "*" });
                cboFields.Items.Add(new DataItem { Text = "Nome do arquivo", Value = "name", Tag = "*" });
                cboFields.Items.Add(new DataItem { Text = "Extensão", Value = "ext", Tag = "" });
                cboFields.SelectedIndex = 0;

                clbFolders.ItemCheck += (o, ev) => SetControls();
                clbFolders.MouseMove += (o, ev) => SetControls();
                clbFolders.LostFocus += (o, ev) => SetControls();

                clbExtensions.ItemCheck += new ItemCheckEventHandler(clbExtensions_ItemCheck);

                txtExtensions.Enter += (o, ev) => ((TextBox)o).SelectAll();

                txtSearchNot.KeyDown += (o, ev) => cboSearch_KeyDown(o, ev);
                txtExtensions.KeyDown += (o, ev) => cboSearch_KeyDown(o, ev);

                grid.AutoGenerateColumns = false;
                grid.AllowUserToOrderColumns = true;
                grid.ReadOnly = true;
                grid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
                grid.SelectionChanged += new EventHandler(grid_SelectionChanged);

                searchers = new Dictionary<int, DocSearcher2>();

                SetControls();
                SetText();

                this.Enter += (o, ev) => cboSearch.Focus();


                this.FindForm().Activated += (o, ev) =>
                    {
                        this.Focus();
                        cboSearch.Focus();
                    };


                // seta os tooltips
                txtTooltipInfo.Text = "";
                //var allControls = Speed.Windows.ControlUtil.GetChildren(this);
                //foreach (var control in allControls)
                //{
                //    var toolTip = toolTip1.GetToolTip(control);
                //    if (!string.IsNullOrEmpty(toolTip))
                //    {
                //        control.MouseEnter += (o, ev) => txtTooltipInfo.Text = toolTip1.GetToolTip((Control)o).Replace ("\r\n", "");
                //        control.MouseLeave += (o, ev) => txtTooltipInfo.Text = "";
                //    }
                //}

                this.FindForm().KeyPreview = true;
                this.FindForm().KeyDown += (o, ev) =>
                {
                    if (ev.KeyCode == Keys.F5)
                        Search(false);
                    if (ev.KeyCode == Keys.F6)
                        Search(true);
                };
            }
        }

        void cboSearch_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
            {
                if (btnSearch.Enabled)
                    Search(false);
            }
        }

        void clbExtensions_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (isSearching)
                return;

            string ext = ((string)clbExtensions.Items[e.Index]).ToLower();

            if (e.NewValue == CheckState.Checked)
            {
                results.AddRange(removed.Where(p => p.Extension.ToLower() == ext));
                removed.RemoveAll(p => p.Extension.ToLower() == ext);
            }
            else
            {
                removed.AddRange(results.Where(p => p.Extension.ToLower() == ext));
                results.RemoveAll(p => p.Extension.ToLower() == ext);
            }

            SetDataSource();

            //// lento demais
            //grid.SuspendLayout();
            //for (int i = 0; i < grid.Rows.Count; i++)
            //{
            //    DocFile file = (DocFile)grid.Rows[i].DataBoundItem;
            //    if (file.Extension.ToLower() == ext)
            //        grid.Rows[i].Height = e.NewValue == CheckState.Checked ? 22 : 0;
            //}
            //grid.ResumeLayout();
        }

        private void lblExtSelectOnlyCurrent_Click(object sender, EventArgs e)
        {
            if (clbExtensions.SelectedItem != null)
            {
                Program.RunSafe(() =>
                {
                    isSearching = true;

                    SelectAll(clbExtensions, false);
                    clbExtensions.SetItemChecked(clbExtensions.SelectedIndex, true);
                    string ext = ((string)clbExtensions.SelectedItem).ToLower();

                    removed.AddRange(results);
                    results.Clear();
                    results.AddRange(removed.Where(p => p.Extension.ToLower() == ext));
                    removed.RemoveAll(p => p.Extension.ToLower() == ext);

                    SetDataSource();
                });
            }
            isSearching = false;
        }

        void grid_SelectionChanged(object sender, EventArgs e)
        {
            if (!isSearching)
            {
                if (grid.SelectedRows.Count > 0)
                {
                    DocFile item = grid.SelectedRows[0].DataBoundItem as DocFile;
                    //if (item != null)
                    //    book.GoToPage(((DocFile)grid.SelectedRows[0].DataBoundItem).PageNumber);
                    SetControls();
                }
            }
        }

        private void cboIndexes_SelectedIndexChanged(object sender, EventArgs e)
        {
            var rowi = (Config.IndexesRow)cboIndexes.SelectedItem;
            clbFolders.Items.Clear();
            foreach (var row in rowi.GetDirectoriesRows())
                clbFolders.Items.Add(new Speed.DataItem { Text = row.DirName, Value = row }, true);
            SetControls();
        }

        private void cboFields_SelectedIndexChanged(object sender, EventArgs e)
        {
            SetControls();
        }

        private void cboSearchMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            SetControls();
        }

        private void Search(bool incremental)
        {
            lblSearching.Visible = true;
            lblSearching.Update();

            try
            {
                string expression = cboSearch.Text.Trim();

                isSearching = true;

                lblResult.Text = "Procurando ...";
                toolTip1.SetToolTip(lblResult, lblResult.Text);

                clbExtensions.Items.Clear();

                DateTime start = DateTime.Now;

                // para nomes de arquivos e caminhos é necessário adicionar '*' para realizar a busca
                string addAst = (string)((DataItem)cboFields.SelectedItem).Tag;
                //if (!string.IsNullOrEmpty(addAst) && !expression.Contains(' ') & !expression.Contains('*'))
                if (!string.IsNullOrEmpty(addAst) && !expression.Contains('*'))
                    expression += "*";

                if (expression.Length == 0)
                    return;

                btnSearch.Enabled = btnSearchInc.Enabled = false;
                this.Cursor = Cursors.WaitCursor;
                if (!cboSearch.Items.Contains(expression))
                    cboSearch.Items.Add(expression);

                grid.DataSource = null;
                var rowi = (Config.IndexesRow)cboIndexes.SelectedItem;
                DocSearcher2 searcher;
                if (!searchers.TryGetValue(rowi.IndexId, out searcher))
                {
                    searcher = new DocSearcher2(rowi.Path);
                    //searcher = new DocSearcher2(EnumLanguage.Brazilian, Program.GetIndexFile(rowi.IndexName));
                    searchers.Add(rowi.IndexId, searcher);
                }

                try
                {
                    EnumSearchMode searchMode = (EnumSearchMode)((DataItem)cboSearchMode.SelectedItem).Value;
                    string field = ((DataItem)cboFields.SelectedItem).Value.ToString();

                    string textRequired = "";
                    if (clbFolders.CheckedItems.Count != clbFolders.Items.Count)
                    {
                        for (int index = 0; index < clbFolders.CheckedItems.Count; index++)
                        {
                            DataItem item = (DataItem)clbFolders.CheckedItems[index];
                            var row = (Config.DirectoriesRow)item.Value;
                            textRequired += "dir: " + row.DirectoryId.ToString();
                            if (index < clbFolders.CheckedItems.Count - 1)
                                textRequired += " OR ";
                        }
                        ToString();
                    }

                    removed = new List<DocFile>();
                    results = searcher.Search(textRequired, txtSearchNot.Text.Trim(), field, expression, searchMode, false, txtExtensions.Text.Trim(), incremental);
                    TimeSpan time = DateTime.Now.Subtract(start);

                    SetDataSource();

                    Dictionary<string, string> exts = new Dictionary<string, string>();
                    foreach (var result in results)
                        if (!exts.ContainsKey(result.Extension.ToLower()))
                            exts.Add(result.Extension.ToLower(), null);

                    clbExtensions.Items.Clear();
                    foreach (var ext in exts.OrderBy(p => p.Key))
                        clbExtensions.Items.Add(ext.Key);
                    SelectAll(clbExtensions, true);

                    lblResult.Text = "Arquivos encontrados: " + results.Count + "   - Tempo: " + Math.Round(time.TotalSeconds, 4) + " s";
                    toolTip1.SetToolTip(lblResult, lblResult.Text);
                }
                catch (Exception ex)
                {
                    lblResult.Text = "Erro: " + ex.Message;
                    toolTip1.SetToolTip(lblResult, lblResult.Text);
                    Program.ShowError("Erro na procura: " + ex.Message);
                }
            }
            catch (Exception ex)
            {
                Program.ShowError(ex);
                lblResult.Text = "Erro: " + ex.Message;
                toolTip1.SetToolTip(lblResult, lblResult.Text);
            }

            lblSearching.Visible = false;

            btnSearch.Enabled = btnSearchInc.Enabled = true;
            this.Cursor = Cursors.Default;
            cboSearch.Focus();
            isSearching = false;
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            Search(false);
        }

        private void btnSearchInc_Click(object sender, EventArgs e)
        {
            Search(true);
        }

        void SelectAll(CheckedListBox list, bool status)
        {
            for (int i = 0; i < list.Items.Count; i++)
                list.SetItemChecked(i, status);
            SetControls();
        }

        void SetControls()
        {
            btnSearch.Enabled = clbFolders.CheckedItems.Count > 0 && !string.IsNullOrEmpty(cboSearch.Text.Trim());
            btnOpenFile.Enabled = btnOpenDir.Enabled = btnCopy.Enabled = btnCopyFiles.Enabled = btnView.Enabled = grid.SelectedRows.Count > 0;
        }

        void SetText(string text = null)
        {
            this.Text = "Procura " + PageIndex + (text == null ? "" : " - " + text);
        }

        private void grid_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
        {
            e.ToString();
        }

        private void grid_Sorted(object sender, EventArgs e)
        {

        }

        private void grid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= 0)
                btnOpenFile_Click(null, null);
        }

        private void btnOpenFile_Click(object sender, EventArgs e)
        {
            btnOpenFile.Enabled = false;
            Program.RunSafe(this, () =>
            {
                for (int index = 0; index < grid.SelectedRows.Count; index++)
                {
                    DocFile item = (DocFile)grid.SelectedRows[index].DataBoundItem;
                    Process.Start(item.FullName);
                }
            });
            btnOpenFile.Enabled = true;
        }

        private void btnOpenDir_Click(object sender, EventArgs e)
        {
            if (grid.CurrentRow == null)
                return;
            btnOpenDir.Enabled = false;
            Program.RunSafe(this, () =>
            {
                {
                    DocFile item = (DocFile)grid.CurrentRow.DataBoundItem;
                    Process.Start(Path.GetDirectoryName(item.FullName));
                }
            });
            btnOpenDir.Enabled = true;

        }

        private void btnCopy_Click(object sender, EventArgs e)
        {
            Program.RunSafe(this, () =>
            {
                if (grid.SelectedRows.Count > 1)
                {
                    StringBuilder b = new StringBuilder();
                    for (int index = 0; index < grid.SelectedRows.Count; index++)
                    {
                        DocFile item = (DocFile)grid.SelectedRows[index].DataBoundItem;
                        b.AppendLine(item.FullName);
                    }
                    Clipboard.SetText(b.ToString());
                }
                else if (grid.SelectedRows.Count == 1)
                    Clipboard.SetText(((DocFile)grid.SelectedRows[0].DataBoundItem).FullName);
            });
        }

        private void btnCopyFiles_Click(object sender, EventArgs e)
        {
            Program.RunSafe(this, () =>
            {
                List<DocFile> files = new List<DocFile>();

                SortableSearchableList<DocFile> list = (SortableSearchableList<DocFile>)grid.DataSource;

                for (int index = 0; index < grid.Rows.Count; index++)
                    if (grid.Rows[index].Selected)
                        files.Add(list[grid.Rows[index].Index]);

                FormCopyFiles.ShoDialog(this, files);
            });
        }

        private void btnView_Click(object sender, EventArgs e)
        {
            Program.RunSafe(this, () =>
            {
                List<string> files = new List<string>();

                foreach (DataGridViewRow row in grid.SelectedRows)
                    files.Add(results[row.Index].FullName);

                int max = 100;
                int count = files.Count;
                FormView.Show(files.Take(max).ToList());
                if (count > max)
                    Program.ShowInformation("Somente os 100 primeiros arquuivos selecionados serão exibidos");
            });
        }

        void SetDataSource()
        {
            grid.DataSource = null;
            grid.DataSource = new SortableSearchableList<DocFile>(results);
        }

        private void grid_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                Program.RunSafe(this, () =>
                    {
                        if (grid.SelectedRows.Count > 0)
                        {
                            var selection = new List<DataGridViewRow>();

                            foreach (DataGridViewRow row in grid.SelectedRows)
                                selection.Add(row);
                            selection = selection.OrderBy(p => p.Index).ToList();

                            if (grid.CurrentCell != null && grid.CurrentCell.Selected)
                                grid.CurrentCell = null;

                            grid.ClearSelection();

                            foreach (DataGridViewRow row in selection)
                                grid.Rows.Remove(row);
                        }
                    });
            }
        }

    }

}
